#pragma once
#include <iostream>

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#include <cstring>

namespace YZC
{
    static const std::string defaultIp = "0.0.0.0";
    class udpServer
    {
    public:
        udpServer(uint16_t port, const std::string &ip = defaultIp)
            : _sockfd(-1), _ip(ip), _port(port) {}

        void init()
        {
            // 1.socket创建套接字,udp需要使用 报文
            _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
            if (_sockfd < 0)
            {
                perror("socket");
                exit(errno);
            }
            printf("socket success\n");

            // 2.绑定fd和端口
            // 首先要设置好通信结构体
            struct sockaddr_in serveraddr;
            memset(&serveraddr, 0, sizeof(serveraddr));
            serveraddr.sin_family = AF_INET;
            serveraddr.sin_addr.s_addr = inet_addr(_ip.c_str()); // 需要转化为大端数据
            serveraddr.sin_port = htons(_port);                  // 需要转化为大端数据
            socklen_t len = sizeof(serveraddr);                  // 设置bind第三个参数

            int n = bind(_sockfd, (struct sockaddr *)&serveraddr, len);
            if (n < 0)
            {
                perror("bind");
                exit(errno);
            }
            printf("bind success\n");
            // UDP在绑定好之后，就能运行了
        }

        void run()
        {
            char buffer[1024];
            while (true)
            {
                // 收数据，要定义对象获取对方的ip和端口
                struct sockaddr_in clientaddr;
                memset(&clientaddr, 0, sizeof(clientaddr));
                socklen_t clientaddrlen = sizeof(clientaddr);

                // recvfrom接收数据
                int count = recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&clientaddr, &clientaddrlen);

                if (count > 0)
                {
                    // 通过设置好的sockaddr获取ip，端口等信息
                    std::string clientip = inet_ntoa(clientaddr.sin_addr);
                    uint16_t clientport = ntohs(clientaddr.sin_port);
                    // 打印收到数据的信息
                    printf("client[%s][%d] --> server:%s\n", clientip.c_str(), clientport, buffer);
                }
                // 清空 buffer
                memset(buffer, 0, sizeof(buffer));
            }
        }

    private:
        int _sockfd; // 通信套接字

        std::string _ip; // 服务器ip
        uint16_t _port;  // 绑定的端口
    };
}
